package me.stone.stanimeclient.core.ui.player

import android.annotation.SuppressLint
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import me.stone.stanimeclient.core.common.extensions.detachParent
import java.lang.ref.SoftReference


class AgeFanVideoSniffer private constructor() {

    companion object {
        private const val DEAD_LINE_OFFSET = 30 * 60 * 1000 // 30分钟过期

        @JvmStatic
        fun <P> create(
            context: P,
            listener: AgeFanVideoGetListener
        ): AgeFanVideoSniffer where P: Context, P: LifecycleOwner {
            return AgeFanVideoSniffer().apply { init(context, context, listener) }
        }
    }

    private lateinit var mWebView: AgeFanSnifferWebView

    private lateinit var mListener: AgeFanVideoGetListener

    private val mObserver = object : DefaultLifecycleObserver {

        override fun onStop(owner: LifecycleOwner) {
            mWebView.clearFocus()
            mWebView.stopLoading()
            mWebView.takeIf { it.canGoBack() }?.goBack()
            mWebView.clearHistory()
        }

        override fun onDestroy(owner: LifecycleOwner) {
            mWebView.detachParent()
            mWebView.removeAllViews()
        }
    }

    private var mLifecycleOwner: SoftReference<LifecycleOwner>? = null
        set(value) {
            field?.get()?.lifecycle?.removeObserver(mObserver)
            field = value
            field?.get()?.lifecycle?.addObserver(mObserver)
        }

    private val mCache: MutableMap<String, CacheVideoItem> = mutableMapOf()

    private fun init(
        context: Context,
        lifecycleOwner: LifecycleOwner,
        listener: AgeFanVideoGetListener
    ) {
        mListener = listener
        mWebView = AgeFanSnifferWebView(context)
        mLifecycleOwner = SoftReference(lifecycleOwner)
    }

    private fun stopLastTask() {
        mWebView.clearFocus()
        mWebView.clearHistory()
        mWebView.takeIf { it.canGoBack() }?.goBack()
        mWebView.clearCache(false)
    }

    private fun putCacheItem(webUrl: String, videoUrl: String) {
        mCache[webUrl] = CacheVideoItem(webUrl, videoUrl)
    }

    private fun getCacheItem(webUrl: String): String? {
        return mCache[webUrl]?.takeUnless { item ->
            item.dead.also { dead ->
                // 如果缓存失效，则清除
                if (dead) mCache.remove(webUrl)
            }
        }?.videoUrl
    }

    fun sniffing(webUrl: String) {
        getCacheItem(webUrl)?.let {
            mListener.onVideoStreamUrlGet(it)
        } ?: let {
            stopLastTask()
            mWebView.videoGetListener = object : AgeFanVideoGetListener {
                override fun onVideoStreamUrlGet(url: String) {
                    putCacheItem(webUrl, url)
                    mListener.onVideoStreamUrlGet(url)
                }
            }
            mWebView.loadUrl(webUrl)
        }
    }

    interface AgeFanVideoGetListener {
        fun onVideoStreamUrlGet(url: String)
    }

    data class CacheVideoItem(
        val webUrl: String,
        val videoUrl: String,
        val deadLine: Long = System.currentTimeMillis() + DEAD_LINE_OFFSET
    ) {
        val dead: Boolean
            get() = System.currentTimeMillis() >= deadLine
    }

    private class AgeFanSnifferWebView (
        context: Context
    ): WebView(context), AgeFanVideoGetListener {

        private val mainThreadExecutor = Handler(Looper.getMainLooper())

        private val videoEventListener = object {
            @JavascriptInterface
            fun onUrlGet(url: String) {
                if (!url.startsWith("blob:http")) {
                    mainThreadExecutor.post { onVideoStreamUrlGet(url) }
                }
            }
        }

        private val js = """
            javascript:
            
            // 搜索 ArtVideo 控件
            function findArtVideo() {
                var documents = document.getElementsByClassName("art-video");
                if (documents.length == 0) {
                    return null;
                }
                return documents[0];
            }

            // 观察器配置
            const config = { childList: true, subtree: true };

            // 观察器回调函数
            const callback = function(mutationsList, observer) {
                var player = findArtVideo();
                if (player != null) {
                    // 获取到 VideoPlayer 后停止监听
                    observer.disconnect();
                    // 获取播放资源
                    var playerSrc = player.src;
                    videoEventListener.onUrlGet(playerSrc);
                }
            }

            // 创建一个观察器实例
            const observer = new MutationObserver(callback);

            // 观察 body 节点是否发生变化
            // 原页面是用 js 构建，当页面加载完成时无法确定 js 是否执行完毕
            // 这里观察 body 变化后尝试获取 video 控件以减少可能存在的误差
            observer.observe(document.body, config);
            
        """.trimIndent()

        init {
            initSetting()
            webViewClient = buildClient()
            addJavascriptInterface(videoEventListener, "videoEventListener")
        }

        var videoGetListener: AgeFanVideoGetListener? = null

        @SuppressLint("SetJavaScriptEnabled")
        private fun initSetting() = settings.apply {
            useWideViewPort = true
            javaScriptEnabled = true
            loadWithOverviewMode = true
        }

        private fun buildClient() = object : WebViewClient() {
            @SuppressLint("JavascriptInterface")
            override fun onPageFinished(view: WebView, url: String) {
                // Timber.d("on page finished -> url: $url")
                view.evaluateJavascript(js) {}
            }

            override fun onLoadResource(view: WebView, url: String) {
                // Timber.d("load resource -> url: $url")
                if (url.endsWith(".m3u8")) {
                    mainThreadExecutor.post { onVideoStreamUrlGet(url) }
                }
            }
        }

        override fun onVideoStreamUrlGet(url: String) {
            videoGetListener?.onVideoStreamUrlGet(url)
            videoGetListener = null
            stopLoading()
            clearFocus()
            clearHistory()
        }
    }
}
